package main

import (
	"context"
	"fmt"
	"sync"
	"time"
)

/**
c := newCancelCtx(parent)
type cancelCtx struct {
	Context

	mu       sync.Mutex            // protects following fields
	done     atomic.Value          // of chan struct{}, created lazily, closed by first cancel call
	children map[canceler]struct{} // set to nil by the first cancel call
	err      error                 // set to non-nil by the first cancel call
}

type Context interface {

	Deadline() (deadline time.Time, ok bool)

	Done() <-chan struct{}

	Err() error

	Value(key any) any
}

type emptyCtx int

func (*emptyCtx) Deadline() (deadline time.Time, ok bool) {
	return
}

func (*emptyCtx) Done() <-chan struct{} {
	return nil
}

func (*emptyCtx) Err() error {
	return nil
}

func (*emptyCtx) Value(key any) any {
	return nil
}

func (e *emptyCtx) String() string {
	switch e {
	case background:
		return "context.Background"
	case todo:
		return "context.TODO"
	}
	return "unknown empty Context"
}

*/

func ContextMain() {
	// 手动取消 Context
	ActivelyCancelCtx()

	// 设置过期或超时时间
	//WithDeadlineCtx()

	// 设置过期时间
	//WithTimeoutCtx()

	// 传递参数
	//WithValueCtx()
}

func WithValueCtx() {
	type TraceCode string

	var wg sync.WaitGroup
	// 设置一个50毫秒的超时
	ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*50)
	// 在系统的入口中设置trace code传递给后续启动的goroutine实现日志数据聚合
	ctx = context.WithValue(ctx, TraceCode("TRACE_CODE"), "12512312234")
	wg.Add(1)
	go func() {
		key := TraceCode("TRACE_CODE")
		traceCode, ok := ctx.Value(key).(string) // 在子goroutine中获取trace code
		if !ok {
			fmt.Println("invalid trace code")
		}
	LOOP:
		for {
			fmt.Printf("worker, trace code:%s\n", traceCode)
			time.Sleep(time.Millisecond * 10) // 假设正常连接数据库耗时10毫秒
			select {
			case <-ctx.Done(): // 50毫秒后自动调用
				break LOOP
			default:
			}
		}
		fmt.Println("worker done!")
		wg.Done()
	}()
	time.Sleep(time.Second * 5)
	cancel() // 此处为超时前主动取消
	wg.Wait()
	fmt.Println("over")
}

func WithTimeoutCtx() {
	ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*50)
	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
	LOOP:
		for {
			fmt.Println("db connecting ...")
			time.Sleep(time.Millisecond * 10) // 假设正常连接数据库耗时10毫秒
			select {
			case <-ctx.Done(): // 50毫秒后自动调用
				break LOOP
			default:
			}
		}
		fmt.Println("worker done!")
		wg.Done()
	}()
	time.Sleep(time.Second * 5)
	cancel() // 通知子goroutine结束
	wg.Wait()
	fmt.Println("over")
}

func WithDeadlineCtx() {
	ctx := context.Background()
	endTime := time.Now().Add(time.Second)
	deadlineCtx, cancelFunc := context.WithDeadline(ctx, endTime)
	waitGroup := sync.WaitGroup{}
	waitGroup.Add(1)
	go func() {
		defer waitGroup.Done()
		after := time.After(time.Millisecond)
		num := 1
		for {
			select {
			case <-after:
				num = 1
				fmt.Println(fmt.Sprintf("over：%d", num))
				return
			case <-deadlineCtx.Done():
				fmt.Println(deadlineCtx.Err())
				return
			default:
				fmt.Println(num)
				num++
			}
		}
	}()
	waitGroup.Wait()
	cancelFunc()
}

func ActivelyCancelCtx() {
	background := context.Background()
	ctx, cancel := context.WithCancel(background)
	waitGroup := sync.WaitGroup{}
	defer func() {
		cancel()
		waitGroup.Wait()
	}()
	// 当我们取完需要的整数后调用cancel
	dst := make(chan int)
	n := 1
	go func() {
		defer waitGroup.Done()
		waitGroup.Add(1)
		sunCtx, _ := context.WithCancel(ctx)
		go func() {
			defer waitGroup.Done()
			waitGroup.Add(1)
			<-sunCtx.Done()
			fmt.Println(fmt.Sprintf("sunCtx:%v", sunCtx.Err()))
			return
		}()
		for {
			select {
			case <-ctx.Done():
				fmt.Println(fmt.Sprintf("parentCtx:%v", ctx.Err()))
				return
			case dst <- n:
				n++
			}
		}
	}()

	for n1 := range dst {
		fmt.Println(n1)
		if n1 == 5 {
			return
		}
	}
}
